using MapsterMapper;
using AiQiuQuan.Sport.Model.Models;
using AiQiuQuan.Sport.Core;
using AiQiuQuan.Sport.WebApi.Entities;
using AiQiuQuan.Sport.WebApi.Repositories;
using Microsoft.EntityFrameworkCore;
using AiQiuQuan.Sport.WebApi.Core;
using AiQiuQuan.Sport.Model.Enums;
using AiQiuQuan.Sport.Model;
using System.Text.Json;

namespace AiQiuQuan.Sport.WebApi.Services.Impl
{
    /// <summary>
    /// 教练管理
    /// </summary>
    public class CoacherService : ICoacherService
    {
        private readonly IMapper _mapper;
        private readonly ICurrentInfo _currentInfo;
        private readonly IUnitOfWorkManager _unitOfWorkManager;
        private readonly ICoacherRepository _coacherRepository;
        private readonly IBaseUserRepository _baseUserRepository;
        private readonly IBaseUserVenueInfoRelationRepository _userVenueInfoRelationRepository;
        private readonly IBaseUserExtendInfoRepository _baseUserExtendInfoRepository;
        private readonly IBaseUserTennisLevelConfigRepository _baseUserTennisLevelConfigRepository;
        private readonly ICourseCoacherRepository _courseCoacherRepository;
        private readonly ICoacherVenueRepository _coacherVenueRepository;
        private readonly IVenueInfoRepository _venueInfoRepository;
        private readonly ICoacherStudentRepository _coacherStudentRepository;
        private readonly ICoacherStudentRecordRepository _coacherStudentRecordRepository;
        private readonly ICoacherBookRepository _coacherBookRepository;
        private readonly ICoacherStarRepository _coacherStarRepository;

        /// <summary>
        /// ctor
        /// </summary>
        public CoacherService(
            IMapper mapper,
            ICoacherRepository coacherRepository,
            ICurrentInfo currentInfo,
            IBaseUserRepository baseUserRepository,
            IBaseUserVenueInfoRelationRepository userVenueInfoRelationRepository,
            IBaseUserExtendInfoRepository baseUserExtendInfoRepository,
            IBaseUserTennisLevelConfigRepository baseUserTennisLevelConfigRepository,
            ICourseCoacherRepository courseCoacherRepository,
            ICoacherVenueRepository coacherVenueRepository,
            IVenueInfoRepository venueInfoRepository,
            ICoacherStudentRepository coacherStudentRepository,
            ICoacherStudentRecordRepository coacherStudentRecordRepository,
            IUnitOfWorkManager unitOfWorkManager,
            ICoacherBookRepository coacherBookRepository,
            ICoacherStarRepository coacherStarRepository)
        {
            _mapper = mapper;
            _currentInfo = currentInfo;
            _coacherRepository = coacherRepository;
            _baseUserRepository = baseUserRepository;
            _userVenueInfoRelationRepository = userVenueInfoRelationRepository;
            _baseUserExtendInfoRepository = baseUserExtendInfoRepository;
            _baseUserTennisLevelConfigRepository = baseUserTennisLevelConfigRepository;
            _courseCoacherRepository = courseCoacherRepository;
            _coacherVenueRepository = coacherVenueRepository;
            _venueInfoRepository = venueInfoRepository;
            _coacherStudentRepository = coacherStudentRepository;
            _coacherStudentRecordRepository = coacherStudentRecordRepository;
            _unitOfWorkManager = unitOfWorkManager;
            _coacherBookRepository = coacherBookRepository;
            _coacherStarRepository = coacherStarRepository;
        }

        /// <summary>
        /// 查询一条记录
        /// </summary>
        public async Task<CoacherDto> GetAsync(Guid id, bool isPlatform = false)
        {
            var queryable = from coacher in _coacherRepository.AsNoTracking()
                            join user in _baseUserRepository.AsNoTracking()
                            on coacher.UserId equals user.ID
                            join tennis1 in _baseUserExtendInfoRepository.AsNoTracking()
                            on user.ID equals tennis1.ID into tennis1d
                            from tennis1 in tennis1d.DefaultIfEmpty()
                            join tennis2 in _baseUserTennisLevelConfigRepository.AsNoTracking()
                            on tennis1.BaseUserTennisLevelConfigID equals tennis2.ID into tennis2d
                            from tennis2 in tennis2d.DefaultIfEmpty()
                            where coacher.ID == id
                            select new CoacherDto
                            {
                                ID = coacher.ID,
                                Type = coacher.Type,
                                UserId = coacher.UserId,
                                IsPlatform = coacher.IsPlatform,
                                Introduction = coacher.Introduction,
                                IsCertificated = coacher.IsCertificated,
                                AddUserId = coacher.AddUserId,
                                AddUserCode = coacher.AddUserCode,
                                IsRecommend = coacher.IsRecommend,
                                IsShow = coacher.IsShow,
                                PicUrl = coacher.PicUrl,
                                U_Code = user.U_Code,
                                U_NickName = user.U_NickName,
                                U_Headportrait = user.U_Headportrait,
                                U_RealName = user.U_RealName,
                                U_PhoneNum = user.U_PhoneNum,
                                TennisLevel = tennis2.LevelName ?? "1.0",
                                CreateTime = coacher.CreateTime,
                            };
            var result = await queryable.FirstOrDefaultAsync();
            if (result != null)
            {
                var venueQueryable = from coacherVenue in _coacherVenueRepository.AsNoTracking()
                                     join venue in _venueInfoRepository.AsNoTracking()
                                     on coacherVenue.VenueId equals venue.ID
                                     where coacherVenue.CoacherId == result.ID
                                     select new CoacherVenueDto
                                     {
                                         ID = coacherVenue.ID,
                                         CoacherId = coacherVenue.CoacherId,
                                         CoacherUserId = coacherVenue.CoacherUserId,
                                         VenueId = coacherVenue.VenueId,
                                         VenueName = venue.VI_Name,
                                         CreateTime = coacherVenue.CreateTime,
                                         IsMain = coacherVenue.IsMain
                                     };
                result.VenueList = await venueQueryable.ToListAsync();
                if (isPlatform)
                {
                    var isManage = await _userVenueInfoRelationRepository.AnyAsync(m => m.BaseUserID == result.AddUserId);
                    var coacher = await _coacherRepository.FirstOrDefaultAsync(m => m.UserId == result.AddUserId);
                    result.AddUserRole = (isManage ? "场馆管理员/" : "").TrimStart('/');
                    result.AddUserRole = coacher != null ? $"{result.AddUserRole}{(coacher.IsPlatform ? "平台" : coacher.Type.ToEnumDescription())}" : "";
                    result.AddUserRole = result.AddUserRole.TrimEnd('/');
                }
                else
                {
                    result.CourseCount = await _courseCoacherRepository.CountAsync(m => m.CoacherId == result.ID);
                }
            }

            return result;
        }

        /// <summary>
        /// 查询
        /// </summary>
        public async Task<CoacherDto> QueryAsync()
        {
            var queryable = from coacher in _coacherRepository.AsNoTracking()
                            join user in _baseUserRepository.AsNoTracking()
                            on coacher.UserId equals user.ID
                            join tennis1 in _baseUserExtendInfoRepository.AsNoTracking()
                            on user.ID equals tennis1.ID into tennis1d
                            from tennis1 in tennis1d.DefaultIfEmpty()
                            join tennis2 in _baseUserTennisLevelConfigRepository.AsNoTracking()
                            on tennis1.BaseUserTennisLevelConfigID equals tennis2.ID into tennis2d
                            from tennis2 in tennis2d.DefaultIfEmpty()
                            where coacher.UserId == _currentInfo.UserId
                            select new CoacherDto
                            {
                                ID = coacher.ID,
                                Type = coacher.Type,
                                UserId = coacher.UserId,
                                IsPlatform = coacher.IsPlatform,
                                Introduction = coacher.Introduction,
                                IsCertificated = coacher.IsCertificated,
                                IsShow = coacher.IsShow,
                                IsRecommend = coacher.IsRecommend,
                                AddUserId = coacher.AddUserId,
                                AddUserCode = coacher.AddUserCode,
                                PicUrl = coacher.PicUrl,
                                U_Code = user.U_Code,
                                U_NickName = user.U_NickName,
                                U_Headportrait = user.U_Headportrait,
                                U_RealName = user.U_RealName,
                                U_PhoneNum = user.U_PhoneNum,
                                TennisLevel = tennis2.LevelName ?? "1.0",
                                CreateTime = coacher.CreateTime,
                                Star = _coacherStarRepository.Where(m => m.CoacherUserId == coacher.UserId).Average(m => m.Star)
                            };
            var result = await queryable.FirstOrDefaultAsync();
            if (result != null)
            {
                var venueQueryable = from coacherVenue in _coacherVenueRepository.AsNoTracking()
                                     join venue in _venueInfoRepository.AsNoTracking()
                                     on coacherVenue.VenueId equals venue.ID
                                     where coacherVenue.CoacherId == result.ID
                                     select new CoacherVenueDto
                                     {
                                         ID = coacherVenue.ID,
                                         CoacherId = coacherVenue.CoacherId,
                                         CoacherUserId = coacherVenue.CoacherUserId,
                                         VenueId = coacherVenue.VenueId,
                                         VenueName = venue.VI_Name,
                                         CreateTime = coacherVenue.CreateTime,
                                     };
                result.VenueList = await venueQueryable.ToListAsync();
                result.CourseCount = await _courseCoacherRepository.CountAsync(m => m.CoacherId == result.ID);
            }

            return result;
        }

        /// <summary>
        /// 分页请求
        /// </summary>
        public async Task<PageResult<CoacherDto>> PageListAsync(CoacherPageRequestDto request)
        {
            var queryable = from coacher in _coacherRepository.AsNoTracking()
                            join user in _baseUserRepository.AsNoTracking()
                            on coacher.UserId equals user.ID
                            join tennis1 in _baseUserExtendInfoRepository.AsNoTracking()
                            on user.ID equals tennis1.ID into tennis1d
                            from tennis1 in tennis1d.DefaultIfEmpty()
                            join tennis2 in _baseUserTennisLevelConfigRepository.AsNoTracking()
                            on tennis1.BaseUserTennisLevelConfigID equals tennis2.ID into tennis2d
                            from tennis2 in tennis2d.DefaultIfEmpty()
                            select new CoacherDto
                            {
                                ID = coacher.ID,
                                Type = coacher.Type,
                                UserId = coacher.UserId,
                                IsPlatform = coacher.IsPlatform,
                                IsCertificated = coacher.IsCertificated,
                                AddUserId = coacher.AddUserId,
                                AddUserCode = coacher.AddUserCode,
                                PicUrl = coacher.PicUrl,
                                U_Code = user.U_Code,
                                U_NickName = user.U_NickName,
                                U_Headportrait = user.U_Headportrait,
                                U_RealName = user.U_RealName,
                                U_PhoneNum = user.U_PhoneNum,
                                TennisLevel = tennis2.LevelName ?? "1.0",
                                ProvinceID = user.ProvinceID,
                                U_P_Name = user.U_P_Name,
                                CityID = user.CityID,
                                U_C_Name = user.U_C_Name,
                                IsShow = coacher.IsShow,
                                CreateTime = coacher.CreateTime,
                            };
            if (!request.IsPlatform)
            {
                queryable = queryable.Where(m => m.IsShow && m.AddUserId == _currentInfo.UserId);
            }

            if (request.ProvinceId.HasValue)
            {
                queryable = queryable.Where(m => m.ProvinceID == request.ProvinceId.Value);
            }

            if (request.CityId.HasValue)
            {
                queryable = queryable.Where(m => m.CityID == request.CityId.Value);
            }

            if (!string.IsNullOrWhiteSpace(request.PhoneNo))
            {
                queryable = queryable.Where(m => m.U_PhoneNum.Contains(request.PhoneNo));
            }

            if (!string.IsNullOrWhiteSpace(request.UserName))
            {
                queryable = queryable.Where(m => m.U_NickName.Contains(request.UserName) || m.U_RealName.Contains(request.UserName));
            }

            if (request.AddUserCode.HasValue)
            {
                queryable = queryable.Where(m => m.AddUserCode == request.AddUserCode.Value);
            }

            var pagelist = await queryable.OrderByDescending(m => m.CreateTime).PageListAsync(request);
            await SetCoacherAttachInfoAsync(request, pagelist.Result);
            return pagelist;
        }

        /// <summary>
        /// 平台分页请求
        /// </summary>
        public async Task<PageResult<CoacherDto>> QueryPageListAsync(CoacherRequestDto request)
        {
            var queryable = from coacher in _coacherRepository.AsNoTracking()
                            join user in _baseUserRepository.AsNoTracking()
                            on coacher.UserId equals user.ID
                            select new CoacherDto
                            {
                                ID = coacher.ID,
                                Type = coacher.Type,
                                UserId = coacher.UserId,
                                IsPlatform = coacher.IsPlatform,
                                IsCertificated = coacher.IsCertificated,
                                U_PhoneNum = user.U_PhoneNum,
                                U_Code = user.U_Code,
                                U_NickName = user.U_NickName,
                                U_Headportrait = user.U_Headportrait,
                                U_RealName = user.U_RealName,
                                CreateTime = coacher.CreateTime,
                            };
            if (!string.IsNullOrWhiteSpace(request.Key))
            {
                int.TryParse(request.Key, out var code);
                queryable = queryable.Where(m => m.U_Code == code || m.U_NickName.Contains(request.Key) || m.U_RealName.Contains(request.Key) || m.U_PhoneNum.Contains(request.Key));
            }
            else
            {
                if (request.Code.HasValue)
                {
                    queryable = queryable.Where(m => m.U_Code == request.Code);
                }

                if (!string.IsNullOrWhiteSpace(request.RealName))
                {
                    queryable = queryable.Where(m => m.U_RealName.Contains(request.RealName));
                }

                if (!string.IsNullOrWhiteSpace(request.NickName))
                {
                    queryable = queryable.Where(m => m.U_NickName.Contains(request.NickName));
                }

                if (!string.IsNullOrWhiteSpace(request.PhoneNo))
                {
                    queryable = queryable.Where(m => m.U_PhoneNum.Contains(request.PhoneNo));
                }
            }

            var pagelist = await queryable.OrderByDescending(m => m.CreateTime).PageListAsync(request);
            return pagelist;
        }

        /// <summary>
        /// 新增
        /// </summary>
        public async Task<UnaryResult> AddAsync(CoacherAddDto model)
        {
            if (!model.IsPlatform)
            {
                if (!await _coacherRepository.AnyAsync(m => m.UserId == _currentInfo.UserId && m.Type == CoacherTypeEnum.Header)
                    && !await _userVenueInfoRelationRepository.AnyAsync(m => _currentInfo.UserId == m.BaseUserID))
                {
                    return UnaryResult.Faild(10, "不是总教练、场馆管理员");
                }
            }

            if (await _coacherRepository.AnyAsync(m => m.UserId == model.UserId))
            {
                return UnaryResult.Faild(10, "重复添加教练");
            }

            var user = await _baseUserRepository.FirstOrDefaultAsync(m => m.ID == _currentInfo.UserId);

            var coacher = new Coacher
            {
                UserId = model.UserId,
                Type = CoacherTypeEnum.Normal,
                IsCertificated = false,
                AddUserId = model.IsPlatform ? new Guid() : _currentInfo.UserId,
                AddUserCode = model.IsPlatform ? 0 : user.U_Code,
                IsPlatform = model.IsPlatform,
                Introduction = string.Empty,
                IsShow = true,
                IsRecommend = false
            };
            await _coacherRepository.AddAsync(coacher);
            return UnaryResult.Succeed();
        }

        /// <summary>
        /// 添加场馆
        /// </summary>
        public async Task<UnaryResult> AddVenueAsync(CoacherVenueAddDto request)
        {
            var coacher = await _coacherRepository.FirstOrDefaultAsync(m => m.UserId == _currentInfo.UserId);
            if (coacher == null)
            {
                return UnaryResult.Faild(10, "当前用户不是教练");
            }

            foreach (var item in request.VenueIdList)
            {
                if (await _coacherVenueRepository.AnyAsync(m => m.CoacherUserId == coacher.UserId && m.VenueId == item))
                {
                    return UnaryResult.Faild(10, "重复添加");
                }
            }

            var list = new List<CoacherVenue>();
            foreach (var item in request.VenueIdList)
            {
                var entity = new CoacherVenue
                {
                    CoacherUserId = coacher.UserId,
                    CoacherId = coacher.ID,
                    VenueId = item,
                    IsMain = false,
                };
                list.Add(entity);
            }

            await _coacherVenueRepository.BulkAddAsync(list);
            return UnaryResult.Succeed();
        }

        /// <summary>
        /// 教练场馆列表
        /// </summary>
        /// <param name="coacherUserId">教练用户ID</param>
        public async Task<List<CoacherVenueDto>> GetCoacherVenueListAsync(Guid coacherUserId)
        {
            var queryable = from coacherVenue in _coacherVenueRepository.AsNoTracking()
                            join venue in _venueInfoRepository.AsNoTracking()
                            on coacherVenue.VenueId equals venue.ID
                            where coacherVenue.CoacherUserId == coacherUserId
                            select new CoacherVenueDto
                            {
                                CoacherUserId = coacherVenue.CoacherUserId,
                                CoacherId = coacherVenue.CoacherId,
                                IsMain = coacherVenue.IsMain,
                                VenueId = coacherVenue.VenueId,
                                VenueName = venue.VI_Name,
                                ID = coacherVenue.ID,
                                CreateTime = coacherVenue.CreateTime
                            };
            return await queryable.ToListAsync();
        }

        /// <summary>
        /// 更新教练场馆
        /// </summary>
        public async Task<UnaryResult> UpdateVenueAsync(CoacherVenueUpdateDto request)
        {
            var coacherVenue = await _coacherVenueRepository.FirstOrDefaultAsync(m => m.ID == request.ID);
            if (coacherVenue == null)
            {
                return UnaryResult.Faild(10, "教练场馆不存在");
            }

            coacherVenue.IsMain = request.IsMain;
            await _coacherVenueRepository.UpdateAsync(coacherVenue);
            return UnaryResult.Succeed();
        }

        /// <summary>
        /// 删除场馆
        /// </summary>
        public async Task<UnaryResult> DeleteVenueAsync(Guid venueId)
        {
            var coacher = await _coacherRepository.FirstOrDefaultAsync(m => m.UserId == _currentInfo.UserId);
            if (coacher == null)
            {
                return UnaryResult.Faild(10, "当前用户不是教练");
            }

            await _coacherVenueRepository.DeleteAsync(m => m.CoacherUserId == coacher.UserId && m.VenueId == venueId);
            return UnaryResult.Succeed();
        }

        /// <summary>
        /// 添加学员
        /// </summary>
        public async Task<UnaryResult> AddStudentAsync(CoacherStudentAddDto request)
        {
            var coacher = await _coacherRepository.FirstOrDefaultAsync(m => m.UserId == _currentInfo.UserId);
            if (coacher == null)
            {
                return UnaryResult.Faild(10, "当前用户不是教练");
            }

            if (await _coacherStudentRepository.AnyAsync(m => m.CoacherUserId == coacher.UserId && m.UserId == request.UserId))
            {
                return UnaryResult.Faild(10, "重复添加");
            }

            var entity = new CoacherStudent
            {
                CoacherUserId = coacher.UserId,
                CoacherId = coacher.ID,
                UserId = request.UserId,
                TimesCount = 0,
            };
            await _coacherStudentRepository.AddAsync(entity);
            return UnaryResult.Succeed();
        }

        /// <summary>
        /// 私教学生删除
        /// </summary>
        public async Task<UnaryResult> DeleteStudentAsync(CoacherStudentDelDto request)
        {
            await _coacherStudentRepository.DeleteAsync(m => m.CoacherUserId == _currentInfo.UserId && m.UserId == request.UserId);
            return UnaryResult.Succeed();
        }

        /// <summary>
        /// 私教学生更新
        /// </summary>
        public async Task<UnaryResult> UpdateStudentAsync(CoacherStudentUpdateDto request)
        {
            var coacher = await _coacherRepository.FirstOrDefaultAsync(m => m.UserId == _currentInfo.UserId);
            if (coacher == null)
            {
                return UnaryResult.Faild(10, "当前用户不是教练");
            }

            if (request.TimesCount < 0)
            {
                return UnaryResult.Faild(10, "学生次数为负");
            }

            var student = await _coacherStudentRepository.FirstOrDefaultAsync(m => m.CoacherUserId == coacher.UserId && m.UserId == request.UserId);
            if (student == null)
            {
                return UnaryResult.Faild(10, "教练学生不存在");
            }

            student.TimesCount = request.TimesCount;
            var record = new CoacherStudentRecordAddDto
            {
                CoacherUserId = student.CoacherUserId,
                UserId = student.UserId,
                TimesCount = student.TimesCount,
                ChangeCount = 0,
                CoacherId = student.CoacherId,
                OperateType = CourseRecordOperateTypeEnum.Update,
                Remark = "更新"
            };
            using (var uow = _unitOfWorkManager.Begin())
            {
                await _coacherStudentRepository.UpdateAsync(student);
                await AddCoacherStudentRecordAsync(record);
                await uow.CompleteAsync();
            }

            return UnaryResult.Succeed();
        }

        /// <summary>
        /// 修改
        /// </summary>
        public async Task<UnaryResult> UpdateAsync(CoacherUpdateDto model)
        {
            var coacher = await _coacherRepository.FirstOrDefaultAsync(m => m.ID == model.ID);
            if (coacher == null)
            {
                return UnaryResult.Faild(10, "教练不存在");
            }

            _mapper.Map(model, coacher);
            if (model.Introduction != null)
            {
                coacher.Introduction = JsonSerializer.Serialize(model.Introduction);
            }

            coacher.Introduction ??= string.Empty;

            //教练场馆
            var list = new List<CoacherVenue>();
            foreach (var item in model.VenueList)
            {
                var entity = new CoacherVenue
                {
                    CoacherUserId = coacher.UserId,
                    CoacherId = coacher.ID,
                    VenueId = item.VenueId,
                    IsMain = item.IsMain,
                    IsRecommend = item.IsRecommend,
                    IsBlack = item.IsBlack,
                };
                list.Add(entity);
            }

            using (var uow = _unitOfWorkManager.Begin())
            {
                await _coacherVenueRepository.DeleteAsync(m => m.CoacherUserId == coacher.UserId);
                await _coacherRepository.UpdateAsync(coacher);
                await _coacherVenueRepository.BulkAddAsync(list);
                await uow.CompleteAsync();
            }

            return UnaryResult.Succeed();
        }

        /// <summary>
        /// 修改图片、介绍
        /// </summary>
        public async Task<UnaryResult> UpdateSimpleAsync(CoacherSimpleUpdateDto model)
        {
            var coacher = _coacherRepository.FirstOrDefault(m => m.ID == model.ID);
            if (coacher == null)
            {
                return UnaryResult.Faild(10, "教练信息不存在");
            }

            if (coacher.UserId != _currentInfo.UserId)
            {
                return UnaryResult.Faild(10, "无权限修改");
            }

            if (model.Introduction != null)
            {
                coacher.Introduction = JsonSerializer.Serialize(model.Introduction);
            }

            if (!string.IsNullOrWhiteSpace(model.PicUrl))
            {
                coacher.PicUrl = model.PicUrl;
            }

            await _coacherRepository.UpdateAsync(coacher);
            return UnaryResult.Succeed();
        }

        /// <summary>
        /// 教练评星
        /// </summary>
        public async Task<UnaryResult> AddStarAsync(CoacherStarAddDto request)
        {
            if (await _coacherStarRepository.AnyAsync(m => m.CoacherUserId == request.CoacherUserId && m.UserId == _currentInfo.UserId))
            {
                return UnaryResult.Faild(10, "重复评价");
            }

            var star = new CoacherStar
            {
                CoacherUserId = request.CoacherUserId,
                UserId = _currentInfo.UserId,
                Star = request.Star
            };
            await _coacherStarRepository.AddAsync(star);
            return UnaryResult.Succeed();
        }

        /// <summary>
        /// 删除
        /// </summary>
        public async Task<UnaryResult> DeleteAsync(Guid id)
        {
            await _coacherRepository.DeleteAsync(p => p.ID == id);
            return UnaryResult.Succeed();
        }

        /// <summary>
        /// 获取私教学生分页列表
        /// </summary>
        public async Task<PageResult<CoacherStudentDto>> GetCoacherStudentPageList(CoacherStudentPageRequestDto request)
        {
            var queryable = from student in _coacherStudentRepository.AsNoTracking()
                            join user in _baseUserRepository.AsNoTracking()
                            on student.UserId equals user.ID
                            where student.CoacherUserId == request.CoacherUserId
                            select new CoacherStudentDto
                            {
                                CoacherUserId = student.CoacherUserId,
                                CoacherId = student.CoacherId,
                                UserId = student.UserId,
                                TimesCount = student.TimesCount,
                                U_Headportrait = user.U_Headportrait,
                                U_NickName = user.U_NickName,
                                U_RealName = user.U_RealName,
                                U_Code = user.U_Code,
                                U_PhoneNum = user.U_PhoneNum,
                                CreateTime = student.CreateTime,
                            };
            var pageList = await queryable.OrderByDescending(m => m.CreateTime).PageListAsync(request);
            return pageList;
        }

        /// <summary>
        /// 获取私教学生记录列表
        /// </summary>
        public async Task<PageResult<CoacherStudentRecordDto>> GetCoacherStudentRecordPageList(CoacherStudentRecordPageRequestDto request)
        {
            var pageList = await _coacherStudentRecordRepository.AsNoTracking()
                .Where(m => m.CoacherUserId == request.CoacherUserId && m.UserId == request.UserId)
                .OrderByDescending(m => m.CreateTime)
                .PageListAsync<CoacherStudentRecord, CoacherStudentRecordDto>(request, _mapper);
            return pageList;
        }

        /// <summary>
        /// 私教学生点名
        /// </summary>
        public async Task<UnaryResult> CallStudentAsync(CoacherStudentRequestDto request)
        {
            foreach (var item in request.CallStudentList)
            {
                if (!await _coacherStudentRepository.AnyAsync(m => m.CoacherUserId == _currentInfo.UserId && m.UserId == item.UserId && m.TimesCount >= item.UseCount))
                {
                    return UnaryResult.Faild(10, "学生次数不足");
                }
            }

            using (var uow = _unitOfWorkManager.Begin())
            {
                foreach (var item in request.CallStudentList)
                {
                    var student = await _coacherStudentRepository.FirstOrDefaultAsync(m => m.CoacherUserId == _currentInfo.UserId && m.UserId == item.UserId);
                    student.TimesCount -= item.UseCount;
                    var addRecord = new CoacherStudentRecordAddDto
                    {
                        CoacherUserId = student.CoacherUserId,
                        CoacherId = student.CoacherId,
                        UserId = student.UserId,
                        ChangeCount = -item.UseCount,
                        TimesCount = student.TimesCount,
                        OperateType = CourseRecordOperateTypeEnum.Call,
                        Remark = "点名"
                    };
                    await _coacherStudentRepository.UpdateAsync(student);
                    await AddCoacherStudentRecordAsync(addRecord);
                }

                await uow.CompleteAsync();
            }

            return UnaryResult.Succeed();
        }

        /// <summary>
        /// 私教预约列表
        /// </summary>
        /// <param name="date">日期</param>
        public async Task<List<CoacherBookGroupDto>> GetCoacherBookingListAsync(DateTimeOffset date)
        {
            var result = new List<CoacherBookGroupDto>();
            var queryable = from book in _coacherBookRepository.AsNoTracking()
                            join user in _baseUserRepository.AsNoTracking()
                            on book.UserId equals user.ID
                            where book.CoacherUserId == _currentInfo.UserId && book.BookDate == date.Date
                            select new CoacherBookDto
                            {
                                ID = book.ID,
                                BusinessId = book.BusinessId,
                                CoacherId = book.CoacherId,
                                CoacherUserId = book.CoacherUserId,
                                UserId = book.UserId,
                                BookDate = book.BookDate,
                                StartTime = book.StartTime,
                                EndTime = book.EndTime,
                                VenueId = book.VenueId,
                                VenueName = book.VenueName,
                                Site = book.Site,
                                State = book.State,
                                CreateTime = book.CreateTime,
                                U_Headportrait = user.U_Headportrait,
                                U_NickName = user.U_NickName,
                                U_PhoneNum = user.U_PhoneNum,
                                U_RealName = user.U_RealName,
                            };
            var list = await queryable.ToListAsync();
            if (list.Any())
            {
                list = list.OrderBy(m => m.StartTime).ToList();
                foreach (var item in list.GroupBy(m => new { m.BookDate, m.StartTime, m.EndTime, m.VenueName, m.Site, m.State, m.VenueId, m.BusinessId }))
                {
                    var groupBook = new CoacherBookGroupDto
                    {
                        BusinessId = item.Key.BusinessId,
                        VenueId = item.Key.VenueId,
                        VenueName = item.Key.VenueName,
                        BookDate = item.Key.BookDate,
                        StartTime = item.Key.StartTime,
                        EndTime = item.Key.EndTime,
                        Site = item.Key.Site,
                        State = item.Key.State,
                        StudentList = item.Select(m => new CoacherBookGroupDetailDto
                        {
                            UserId = m.UserId,
                            U_Headportrait = m.U_Headportrait,
                            U_NickName = m.U_NickName,
                            U_PhoneNum = m.U_PhoneNum,
                            U_RealName = m.U_RealName
                        }).ToList()
                    };
                    result.Add(groupBook);
                }
            }

            return result;
        }

        /// <summary>
        /// 我的私教预约列表
        /// </summary>
        public async Task<List<CoacherBookDto>> GetMyCoacherBookingListAsync(MyCoacherBookRequestDto request)
        {
            var bookStateList = new List<CoacherBookStateEnum> { CoacherBookStateEnum.Processing, CoacherBookStateEnum.Cancel };
            var queryable = from book in _coacherBookRepository.AsNoTracking()
                            where book.UserId == _currentInfo.UserId && bookStateList.Contains(book.State)
                            select new CoacherBookDto
                            {
                                ID = book.ID,
                                BusinessId = book.BusinessId,
                                CoacherId = book.CoacherId,
                                CoacherUserId = book.CoacherUserId,
                                UserId = book.UserId,
                                BookDate = book.BookDate,
                                StartTime = book.StartTime,
                                EndTime = book.EndTime,
                                VenueId = book.VenueId,
                                VenueName = book.VenueName,
                                Site = book.Site,
                                State = book.State,
                                CreateTime = book.CreateTime
                            };
            if (request.BookDate.HasValue)
            {
                queryable = queryable.Where(m => m.BookDate == request.BookDate.Value.Date);
            }
            else
            {
                var start = DateTime.Now.Date;
                var end = start.AddDays(6);
                queryable = queryable.Where(m => m.BookDate >= start && m.BookDate <= end);
            }

            var list = await queryable.ToListAsync();
            return list;
        }

        /// <summary>
        /// 私教预约详情
        /// </summary>
        /// <param name="businessId">业务ID</param>
        public async Task<CoacherBookGroupDto> GetCoacherBookingAsync(Guid businessId)
        {
            CoacherBookGroupDto result = null;
            var queryable = from book in _coacherBookRepository.AsNoTracking()
                            join user in _baseUserRepository.AsNoTracking()
                            on book.UserId equals user.ID
                            where book.BusinessId == businessId
                            select new CoacherBookDto
                            {
                                ID = book.ID,
                                BusinessId = book.BusinessId,
                                CoacherId = book.CoacherId,
                                CoacherUserId = book.CoacherUserId,
                                UserId = book.UserId,
                                BookDate = book.BookDate,
                                StartTime = book.StartTime,
                                EndTime = book.EndTime,
                                VenueId = book.VenueId,
                                VenueName = book.VenueName,
                                Site = book.Site,
                                State = book.State,
                                CreateTime = book.CreateTime,
                                U_Headportrait = user.U_Headportrait,
                                U_NickName = user.U_NickName,
                                U_PhoneNum = user.U_PhoneNum,
                                U_RealName = user.U_RealName,
                            };
            var list = await queryable.ToListAsync();
            if (list.Any())
            {
                foreach (var item in list.GroupBy(m => new { m.BookDate, m.StartTime, m.EndTime, m.VenueName, m.Site, m.State, m.VenueId, m.BusinessId }))
                {
                    result = new CoacherBookGroupDto
                    {
                        BusinessId = item.Key.BusinessId,
                        VenueId = item.Key.VenueId,
                        VenueName = item.Key.VenueName,
                        BookDate = item.Key.BookDate,
                        StartTime = item.Key.StartTime,
                        EndTime = item.Key.EndTime,
                        Site = item.Key.Site,
                        State = item.Key.State,
                        StudentList = item.Select(m => new CoacherBookGroupDetailDto
                        {
                            UserId = m.UserId,
                            U_Headportrait = m.U_Headportrait,
                            U_NickName = m.U_NickName,
                            U_PhoneNum = m.U_PhoneNum,
                            U_RealName = m.U_RealName
                        }).ToList()
                    };
                }
            }

            return result;
        }

        /// <summary>
        /// 私教预约增加
        /// </summary>
        public async Task<UnaryResult> AddCoacherBookingAsync(CoacherBookAddDto request)
        {
            var coacher = await _coacherRepository.AsNoTracking().FirstOrDefaultAsync(m => m.UserId == _currentInfo.UserId);
            if (coacher == null)
            {
                return UnaryResult.Faild(10, "当前用户不是教练");
            }

            var list = await _coacherBookRepository.AsNoTracking()
                .Where(m => m.CoacherUserId == coacher.UserId && m.BookDate == request.BookDate.Date && m.State == CoacherBookStateEnum.Processing).ToListAsync();
            if (list.Any(m => TimeSpan.Parse(m.StartTime) < TimeSpan.Parse(request.EndTime) && TimeSpan.Parse(m.EndTime) > TimeSpan.Parse(request.StartTime)))
            {
                return UnaryResult.Faild(10, "时间跨度重复");
            }

            var venune = await _venueInfoRepository.AsNoTracking().FirstOrDefaultAsync(m => m.ID == request.VenueId);
            var businessId = Guid.NewGuid();
            list.Clear();
            foreach (var item in request.StudentIdList)
            {
                var book = new CoacherBook
                {
                    BusinessId = businessId,
                    CoacherId = coacher.ID,
                    CoacherUserId = coacher.UserId,
                    BookDate = request.BookDate.Date,
                    StartTime = request.StartTime,
                    EndTime = request.EndTime,
                    VenueId = venune.ID,
                    VenueName = venune.VI_Name,
                    Site = request.Site,
                    State = CoacherBookStateEnum.Processing,
                    UserId = item
                };
                list.Add(book);
            }

            await _coacherBookRepository.BulkAddAsync(list);
            return UnaryResult.Succeed();
        }

        /// <summary>
        /// 私教预约更新
        /// </summary>
        public async Task<UnaryResult> UpdateCoacherBookingAsync(CoacherBookUpdateDto request)
        {
            var coacher = await _coacherRepository.AsNoTracking().FirstOrDefaultAsync(m => m.UserId == _currentInfo.UserId);
            if (coacher == null)
            {
                return UnaryResult.Faild(10, "当前用户不是教练");
            }

            var oldBooking = await _coacherBookRepository.AsNoTracking().FirstOrDefaultAsync(m => m.BusinessId == request.BusinessId);
            if (oldBooking == null)
            {
                return UnaryResult.Faild(10, "预约信息不存在");
            }

            if (oldBooking.State != CoacherBookStateEnum.Processing)
            {
                return UnaryResult.Faild(10, "预约信息状态非进行中");
            }

            var list = await _coacherBookRepository.AsNoTracking()
                .Where(m => m.CoacherUserId == coacher.UserId && m.BookDate == oldBooking.BookDate.Date && m.BusinessId != oldBooking.BusinessId)
                .ToListAsync();
            if (list.Any(m => TimeSpan.Parse(m.StartTime) < TimeSpan.Parse(request.EndTime) && TimeSpan.Parse(m.EndTime) > TimeSpan.Parse(request.StartTime)))
            {
                return UnaryResult.Faild(10, "时间跨度重复");
            }

            var venune = await _venueInfoRepository.AsNoTracking().FirstOrDefaultAsync(m => m.ID == request.VenueId);
            list.Clear();
            foreach (var item in request.StudentIdList)
            {
                var book = new CoacherBook
                {
                    BusinessId = oldBooking.BusinessId,
                    CoacherId = oldBooking.CoacherId,
                    CoacherUserId = oldBooking.CoacherUserId,
                    BookDate = oldBooking.BookDate.Date,
                    StartTime = request.StartTime,
                    EndTime = request.EndTime,
                    VenueId = venune.ID,
                    VenueName = venune.VI_Name,
                    Site = request.Site,
                    State = oldBooking.State,
                    UserId = item
                };
                list.Add(book);
            }

            using (var uow = _unitOfWorkManager.Begin())
            {
                await _coacherBookRepository.DeleteAsync(m => m.BusinessId == oldBooking.BusinessId);
                await _coacherBookRepository.BulkAddAsync(list);
                await uow.CompleteAsync();
            }

            return UnaryResult.Succeed();
        }

        /// <summary>
        /// 私教预约状态更新
        /// </summary>
        public async Task<UnaryResult> UpdateCoacherBookingStateAsync(CoacherBookStateUpdateDto request)
        {
            var builder = await _coacherBookRepository.UpdatePartialAsync();
            await builder.Set(m => m.State, request.State).Where(m => m.BusinessId == request.BusinessId).ExecuteAsync();
            return UnaryResult.Succeed();
        }

        #region private methods
        /// <summary>
        /// 教练额外信息
        /// </summary>
        private async Task SetCoacherAttachInfoAsync(CoacherPageRequestDto request, IList<CoacherDto> list)
        {
            foreach (var item in list)
            {
                item.CourseCount = await _courseCoacherRepository.CountAsync(m => m.CoacherId == item.ID);
                item.PersonalStudentCount = await _coacherStudentRepository.CountAsync(m => m.CoacherId == item.ID);
                if (request.IsPlatform)
                {
                    if (item.IsPlatform)
                    {
                        item.AddUserRole = "平台";
                    }
                    else
                    {
                        var isManage = await _userVenueInfoRelationRepository.AnyAsync(m => m.BaseUserID == item.AddUserId);
                        var coacher = await _coacherRepository.FirstOrDefaultAsync(m => m.UserId == item.AddUserId);
                        item.AddUserRole = (isManage ? "场馆管理员/" : "").TrimStart('/');
                        item.AddUserRole = coacher != null ? $"{item.AddUserRole}{coacher.Type.ToEnumDescription()}" : "";
                        item.AddUserRole = item.AddUserRole.TrimEnd('/');
                    }

                    item.VenueCount = await _coacherVenueRepository.CountAsync(m => m.CoacherId == item.ID);
                }
            }
        }

        /// <summary>
        /// 私教学生记录
        /// </summary>
        private async Task AddCoacherStudentRecordAsync(CoacherStudentRecordAddDto model)
        {
            var record = _mapper.Map<CoacherStudentRecord>(model);
            await _coacherStudentRecordRepository.AddAsync(record);
        }
        #endregion
    }
}
